package com.yxw.bamboo.core.database.mysql;

import com.mysql.jdbc.CharsetMapping;
import com.yxw.bamboo.core.Buffer;
import com.yxw.bamboo.core.BytesHelper;
import com.yxw.bamboo.core.SocketChannel;
import com.yxw.bamboo.core.database.BytesConvert;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

@Component
public class MysqlBytesConvert implements BytesConvert {

    static final int CLIENT_PROTOCOL_41 = 0x00000200;
    /**
     *用户名后面会添加一个0btye 的数据 通过查找第一个0byte来确定用户名
     * @param des
     * @return
     */
    public byte[] findUserNameByte(byte[] des, SocketChannel channel)
    {
        int lenght=0;
        for (byte b:des) {

            if(b==0)
            {
                break;
            }
            lenght++;
        }

        byte[] result=new byte[lenght];
        System.arraycopy(des, 0, result, 0, lenght);

        return  result;
    }

    public  void getSqlDbAndUserName(byte[] userDbBytes, int hashcode, String[] sqlPWDPluginNames, SocketChannel channel) throws UnsupportedEncodingException {
        //File userDbfile = new File(filePathe);
        //byte[] userDbBytes=fileToBinArray(userDbfile);
        //4位头部+4位clientparm+4位最大字节数+1位编码类型+23位0.总共36位+用户名+byte 0+key长度+（加密key+加密字符串）+ 数据库名称+加密组件名称+
        //+客户端connect属性
        int firstCharDbUserIndx=35;
        int charIndex=(int)userDbBytes[12];
        int length=userDbBytes.length-36;
        byte[] des=new byte[length];
        String charSet= CharsetMapping.getJavaEncodingForCollationIndex(charIndex);
        System.arraycopy(userDbBytes, firstCharDbUserIndx+1, des, 0, length);

        byte[]userNameBytes=findUserNameByte(des,channel);
        String userName=new String(userNameBytes,charSet);

        int pwdDesByteLength=des.length-userNameBytes.length;
        byte[]dbNameBytes=new byte[pwdDesByteLength];
        System.arraycopy(des, userNameBytes.length, dbNameBytes, 0, pwdDesByteLength);

        String sqlPWDPluginName="";
        int sqlPWDIndex=-1;
        for (String sqlPWDPluginNameItem:sqlPWDPluginNames
        ) {
            byte[] sqlPWDPluginNameBytes=sqlPWDPluginNameItem.getBytes(charSet);
            sqlPWDIndex= BytesHelper.getByteIndexOf(dbNameBytes,sqlPWDPluginNameBytes,0,dbNameBytes.length-1);
            if(sqlPWDIndex>-1)
            {
                sqlPWDPluginName=sqlPWDPluginNameItem;
                break;
            }
        }

        if(sqlPWDIndex<=-1)
        {
            System.out.println(hashcode+"---"+"未能找到plugin name!!!");
        }else
        {
            byte[] dbStringWithPwdBytes=new byte[sqlPWDIndex];

            System.arraycopy(dbNameBytes, 0, dbStringWithPwdBytes, 0, sqlPWDIndex);
            String dbStringWithPwd=new String(dbStringWithPwdBytes,charSet);

            channel.getDbINfo().setUserName(userName);
            channel.getDbINfo().setDbNameBytes(dbStringWithPwdBytes);
            channel.getDbINfo().setDbName(dbStringWithPwd);
            System.out.println(hashcode+"---"+"用户名:"+userName);

            System.out.println(hashcode+"---"+"加密密码和明文数据库名称:"+dbStringWithPwd);
        }

    }

    @Override
    public int getServerCapabilities(byte[] des) throws Exception {
        int serverMajorVersion = 0;
        int serverMinorVersion = 0;
        int serverSubMinorVersion = 0;
        int maxThreeBytes = 255 * 255 * 255;
        boolean useNewLargePackets = false;
        boolean colDecimalNeedsBump = false;
        boolean useNewUpdateCounts=false;
        int serverCharsetIndex;
        int serverCapabilities;
        String seed;
        long threadId=0;
        int serverStatus = 0;
        // Get the protocol version
        Buffer buf=new Buffer(des);
        byte protocolVersion =buf.readByte();

        if(protocolVersion==-1)
        {
            throw new Exception("服务的错误！！");
        }

        String serverVersion= buf.readString("ASCII", null);

        // Parse the server version into major/minor/subminor
        int point = serverVersion.indexOf('.');

        if (point != -1) {
            try {
                int n = Integer.parseInt(serverVersion.substring(0, point));
                serverMajorVersion = n;
            } catch (NumberFormatException NFE1) {
                // ignore
            }

            String remaining = serverVersion.substring(point + 1, serverVersion.length());
            point = remaining.indexOf('.');

            if (point != -1) {
                try {
                    int n = Integer.parseInt(remaining.substring(0, point));
                    serverMinorVersion = n;
                } catch (NumberFormatException nfe) {
                    // ignore
                }

                remaining = remaining.substring(point + 1, remaining.length());

                int pos = 0;

                while (pos < remaining.length()) {
                    if ((remaining.charAt(pos) < '0') || (remaining.charAt(pos) > '9')) {
                        break;
                    }

                    pos++;
                }

                try {
                    int n = Integer.parseInt(remaining.substring(0, pos));
                    serverSubMinorVersion = n;
                } catch (NumberFormatException nfe) {
                    // ignore
                }
            }
        }

        if (versionMeetsMinimum(4, 0, 8,serverMajorVersion,serverMinorVersion,serverSubMinorVersion)) {
            maxThreeBytes = (256 * 256 * 256) - 1;
            useNewLargePackets = true;
        } else {
            maxThreeBytes = 255 * 255 * 255;
            useNewLargePackets = false;
        }

        colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0,serverMajorVersion,serverMinorVersion,serverSubMinorVersion);
        colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15,serverMajorVersion,serverMinorVersion,serverSubMinorVersion); // guess? Not noted in changelog
        useNewUpdateCounts = versionMeetsMinimum(3, 22, 5,serverMajorVersion,serverMinorVersion,serverSubMinorVersion);

        // read connection id
        threadId = buf.readLong();

        if (protocolVersion > 9) {
            // read auth-plugin-data-part-1 (string[8])
            seed = buf.readString("ASCII", null, 8);
            // read filler ([00])
            buf.readByte();
        } else {
            // read scramble (string[NUL])
            seed = buf.readString("ASCII",null);
        }

        serverCapabilities = 0;

        // read capability flags (lower 2 bytes)
        if (buf.getPosition() < buf.getBufLength()) {
            serverCapabilities = buf.readInt();
        }


        if ((versionMeetsMinimum(4, 1, 1,serverMajorVersion,serverMinorVersion,serverSubMinorVersion) || ((protocolVersion > 9) && (serverCapabilities & CLIENT_PROTOCOL_41) != 0))) {

            /* New protocol with 16 bytes to describe server characteristics */
            // read character set (1 byte)
            serverCharsetIndex = buf.readByte() & 0xff;
            // read status flags (2 bytes)
            serverStatus = buf.readInt();

            // read capability flags (upper 2 bytes)
            serverCapabilities |= buf.readInt() << 16;
        }


        return serverCapabilities;
    }


    /**
     * Does the version of the MySQL server we are connected to meet the given
     * minimums?
     *
     * @param major
     * @param minor
     * @param subminor
     */
    boolean versionMeetsMinimum(int major, int minor, int subminor,
                                int serverMajorVersion,int serverMinorVersion,int serverSubMinorVersion) {
        if (serverMajorVersion >= major) {
            if (serverMajorVersion == major) {
                if (serverMinorVersion >= minor) {
                    if (serverMinorVersion == minor) {
                        return (serverSubMinorVersion >= subminor);
                    }

                    // newer than major.minor
                    return true;
                }

                // older than major.minor
                return false;
            }

            // newer than major
            return true;
        }

        return false;
    }

}
